﻿using System;
using System.Collections;
using CookComputing.XmlRpc;
using System.Timers;
using System.Net;
using System.IO;

using MediaPortal.GUI.Library;
using MediaPortal.Profile;

namespace MyLeech
{
  public struct status
  {
    public string version;
    public string uptime;
    public DateTime time;
    public bool is_paused;
    public int rate;
    public int queued_mb;
    public int eta;
    public int percent_complete;
    public int maxrate;
    public int total_dl_nzbs;
    public int total_dl_files;
    public int total_dl_segments;
    public int total_dl_mb;
    public string config_file;
    public XmlRpcStruct[] currently_downloading;
    public XmlRpcStruct[] currently_processing;
    public XmlRpcStruct[] queued; //can be done outside status command
  }

  public struct paused
  {
    public bool is_paused;
  }
  public struct Continue
  {
    public bool is_paused;
  }
  struct statusTimer
  {
    public Timer tmrTimer;
    public bool KeepAlive;
  }
  //take this out
  struct DirectoryWatch
  {
    public Timer tmrTimer;
  }
  struct JOBQueue
  {
    public Timer tmrTimer;
  }
  [XmlRpcUrl("http://localhost:8760")] //xmlrpc server location
  public interface HellaNZB_API : IXmlRpcProxy
  {
    [XmlRpcMethod("status")] //get status
    status status();
    [XmlRpcMethod("pause")] //paused queue
    paused pause();
    [XmlRpcMethod("continue")] //continue from paused
    Continue Continue();
    [XmlRpcMethod("cancel")] //cancel current download
    status cancel();
    [XmlRpcMethod("force")] //for queued item to download
    status force_download(string id);
    [XmlRpcMethod("up")] //move queued item up
    XmlRpcStruct[] Move_Up(string id);
    [XmlRpcMethod("down")] //move queued item down
    XmlRpcStruct[] Move_Down(string id);
    [XmlRpcMethod("next")] //move queued item to next in line
    XmlRpcStruct[] Move_Next(string id);
    [XmlRpcMethod("last")] //move queued item to end of queue
    XmlRpcStruct[] Move_Last(string id);
    [XmlRpcMethod("dequeue")] //remove queued item from queue
    XmlRpcStruct[] Dequeue(string id);

  }

  class HELLANZB_FUNC
  {
    private mediaportalFunc Dialogs = new mediaportalFunc();
    private bool CHECK_HELLANZB = true; 
    public HellaNZB_API connect_xml()
    {
      HellaNZB_API API = XmlRpcProxyGen.Create<HellaNZB_API>(); //XMLRPC API
      API.Expect100Continue = true;
      API.KeepAlive = false;
      API.Credentials = new NetworkCredential("hellanzb", "changeme");
      return API;
    }
    public status getStatus(statusTimer Status, GUIToggleButtonControl btnButton)
    {
      ///check to see if HELLANZB is running.
      if (CHECK_HELLANZB)
      {
        Settings mpSettings = new Settings(MediaPortal.Configuration.Config.GetFolder(MediaPortal.Configuration.Config.Dir.Config) + @"\MyLeech.xml");
        bool python = false;
        foreach (System.Diagnostics.Process process in System.Diagnostics.Process.GetProcesses())
        {//get list of running processes
          if (process.ProcessName.IndexOf("pythonw") > -1 || process.ProcessName.IndexOf("python") > -1) python = true;
        }
        if (!python & mpSettings.GetValueAsBool("#Hellanzb", "allow_start", false))
        {//if no pythonw then that means no HellaNZB so start it
          System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
          psi.WorkingDirectory = mpSettings.GetValueAsString("#Hellanzb", "location", @"C:\hellanzb") + @"\system";
          psi.FileName = mpSettings.GetValue("#Hellanzb", "python"); ;

          psi.Arguments = mpSettings.GetValueAsString("#Hellanzb", "location", @"C:\hellanzb") + @"\system\hellanzb.py";
          psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
          psi.UseShellExecute = false;
          System.Diagnostics.Process.Start(psi);
          status BLANK = new status();
          this.CHECK_HELLANZB = false;
          mpSettings.Dispose();
          return BLANK;
        }
        this.CHECK_HELLANZB = false;
      }
        
      
      status STATUS = new status();
      try
      { //will throw errors if the server is not running

        HellaNZB_API API = connect_xml();
        
        //*************To Do: Read Hellanzb config file for XMLRPC login info
        STATUS = API.status(); //Request Status from Hellanzb and put into our STRUCT
        string status_label = String.Empty;
        string queue_status = String.Empty;
        if (STATUS.is_paused == true) //disable the timer and enable the Pause GUI btn.
        {
          Status.tmrTimer.Enabled = false;
          btnButton.Selected = true;
        }
        if (STATUS.is_paused == false && STATUS.currently_downloading.Length > 0) { status_label = "Downloading..."; }
        if (STATUS.is_paused == true && STATUS.currently_downloading.Length > 0) { status_label = "Paused. Downloads Waiting"; }
        if (STATUS.is_paused == false && STATUS.currently_downloading.Length < 1) { status_label = "Idle."; }
        if (STATUS.is_paused == true && STATUS.currently_downloading.Length < 1) { status_label = "Paused. Idle."; }

        queue_status = "Idle.";
        if (STATUS.queued.Length > 0) { queue_status = (STATUS.queued.Length).ToString() + " + 1 DL"; }
        if (STATUS.queued.Length == 0 && STATUS.currently_downloading.Length > 0) { queue_status = "0 + 1 DL"; }

        TimeSpan ts = TimeSpan.FromSeconds(STATUS.eta);
        string s = (ts.Days * 24 + ts.Hours).ToString()
           + ":" + ts.Minutes.ToString()
           + ":" + ts.Seconds.ToString();
        //Typical update status.
        GUIPropertyManager.SetProperty("#status", "STATUS: " + status_label);
        GUIPropertyManager.SetProperty("#KBps", "RATE: " + STATUS.rate.ToString() + " KB/s");
        GUIPropertyManager.SetProperty("#Percent", "PERCENT: " + STATUS.percent_complete.ToString() + "%");
        GUIPropertyManager.SetProperty("#JobCount", "QUEUED: " + queue_status);
        GUIPropertyManager.SetProperty("#eta", "ETA: " + s);
      }
      catch (Exception ex)
      {
        //Status.tmrTimer.Enabled = false;
        Log.Info("Data: " + ex.Data);
        Log.Info("HelpLink: " + ex.HelpLink);
        Log.Info("InnerException: " + ex.InnerException);
        Log.Info("Message: " + ex.Message);
        Log.Info("Source: " + ex.Source);
        Log.Info("StackTrace: " + ex.StackTrace);
        Log.Info("TargetSite: " + ex.TargetSite);
      }
      return STATUS;
    }
    public void Pause(bool BoolPause, statusTimer Status)
    {
      try
      {

        HellaNZB_API API = connect_xml();
        //*************To Do: Read Hellanzb config file for XMLRPC login info
        
        if (BoolPause)
        { //pause
          API.pause(); //send pause command
          GUIPropertyManager.SetProperty("#Status", "Queue paused.");
        }
        else
        {
          API.Continue(); //send continue command
          Status.tmrTimer.Enabled = true;
          GUIPropertyManager.SetProperty("#Status", "Queue resumed.");
        }
      }
      catch (Exception ex)
      {
        Status.tmrTimer.Enabled = false;
        Log.Info("Data: " + ex.Data);
        Log.Info("HelpLink: " + ex.HelpLink);
        Log.Info("InnerException: " + ex.InnerException);
        Log.Info("Message: " + ex.Message);
        Log.Info("Source: " + ex.Source);
        Log.Info("StackTrace: " + ex.StackTrace);
        Log.Info("TargetSite: " + ex.TargetSite);
      }
    }
    public void SEND_OPTION(string id, string DO, statusTimer Status)
    {
      try
      {
        HellaNZB_API API = connect_xml();
        switch (DO)
        {
          case "Force": API.force_download(id); break;
          case "Move_Up": API.Move_Up(id); break;
          case "Move_Down": API.Move_Down(id); break;
          case "Move_Next": API.Move_Next(id); break;
          case "Move_Last": API.Move_Last(id); break;
          case "Dequeue": API.Dequeue(id); break;
          case "Cancel": API.cancel(); break;
          default: return;
        }
      }
      catch (Exception ex)
      {
        Status.tmrTimer.Enabled = false;
        Log.Info("Data: " + ex.Data);
        Log.Info("HelpLink: " + ex.HelpLink);
        Log.Info("InnerException: " + ex.InnerException);
        Log.Info("Message: " + ex.Message);
        Log.Info("Source: " + ex.Source);
        Log.Info("StackTrace: " + ex.StackTrace);
        Log.Info("TargetSite: " + ex.TargetSite);
      }

    }
    public void Watch_Dir(DirectoryWatch DIR_WATCH)
    {
      try
      {
        //Stop timer
        //DIR_WATCH.tmrTimer.Enabled = false;
        //load video and music folder
        Settings mpSettings = new Settings(MediaPortal.Configuration.Config.GetFolder(MediaPortal.Configuration.Config.Dir.Config) + @"\MyLeech.xml");
        if (mpSettings.GetValueAsBool("#Plugin", "move_files",false) == false) { return; }
        if (mpSettings.GetValueAsString("#Hellanzb", "location","null").Length < 8) { return; }
        else
        {
          if (Directory.Exists((mpSettings.GetValue("#Hellanzb", "location")) + @"\finished"))
          {
            string BASE_DIR = (mpSettings.GetValue("#Hellanzb", "location")) + @"\finished";
            string MUSIC_DIR = mpSettings.GetValue("#Plugin", "music_folder");
            string VIDEO_DIR = mpSettings.GetValue("#Plugin", "video_folder");
            if (MUSIC_DIR.Length < 10) { return; }
            if (VIDEO_DIR.Length < 10) { return; }
            string[] SONG_EXT = new string[] { "*.mp3","*.wma","*.mp4","*.ogg","*.flac","*.wav" };
            string[] VIDEO_EXT = new string[] { "*.avi", "*.mpg", "*.mpeg", "*.mkv", "*.rm", "*.wmv", "*.divx", "*.ogv" };
            DirectoryInfo Main_Dir = new DirectoryInfo(BASE_DIR);
            Random RandomClass = new Random();
            //############## SINGLE FILES ####################
            foreach (string Filter in SONG_EXT)
            {
              FileInfo[] Music_Files = Main_Dir.GetFiles(Filter);
              string m_file = "";
              foreach (FileInfo F in Music_Files)
              {
                //Make sure the file doesn't already exist.
                m_file = "";
                if (File.Exists(MUSIC_DIR + @"\" + F.Name)) { m_file = MUSIC_DIR + @"\" + F.Name + RandomClass.Next(4, 14); }
                else { m_file = MUSIC_DIR + @"\"+F.Name; }
                File.Move(F.FullName, m_file);
              }
            }
            
            foreach (string Filter in VIDEO_EXT)
            {
              FileInfo[] Video_Files = Main_Dir.GetFiles(Filter);
              string v_file = "";
              foreach (FileInfo F in Video_Files)
              {
                v_file = "";
                if (File.Exists(VIDEO_DIR + @"\" + F.Name)) { v_file = VIDEO_DIR + @"\" + F.Name + RandomClass.Next(4, 14); ; }
                else { v_file = VIDEO_DIR + @"\"+F.Name; }
                File.Move(F.FullName, v_file);
              }
            }
            //now, ONE deep directory search
            DirectoryInfo[] Subs = Main_Dir.GetDirectories();
            ArrayList DIRS_TO_MOVE = new ArrayList(); //list of directories to move
            ArrayList DIRS_NEW_NAME = new ArrayList(); //list of new locations
            foreach (DirectoryInfo D in Subs)
            {
                foreach(string mFilter in SONG_EXT)
                {     
                  FileInfo[] Music_Files = D.GetFiles(mFilter);
                  if (Music_Files.Length > 0)
                  {
                    DIRS_TO_MOVE.Add(D.FullName);
                    DIRS_NEW_NAME.Add(MUSIC_DIR + @"\" + D.Name);
                    break;  
                  }
                  
                }
                
                foreach (string vFilter in VIDEO_EXT)
                {
                  FileInfo[] Video_Files = D.GetFiles(vFilter);
                  if (Video_Files.Length > 0)
                  {
                    DIRS_TO_MOVE.Add(D.FullName);
                    DIRS_NEW_NAME.Add(VIDEO_DIR + @"\" + D.Name);
                    break; //if we've found a known video type, break out of loop
                  }
                }
            }
            //MOVE DIRECTORIES
            for (int i = 0; i < DIRS_TO_MOVE.Count; i++) {
              if (Directory.Exists(DIRS_NEW_NAME[i].ToString()) == false) //stop errors
              {
                Directory.Move(DIRS_TO_MOVE[i].ToString(), DIRS_NEW_NAME[i].ToString());
              }
              else
              {
                DirectoryInfo Read_Dir = new DirectoryInfo(DIRS_TO_MOVE[i].ToString());
                string N_file = "";
                ArrayList DELETE = new ArrayList();
                FileInfo[] N_Files = Read_Dir.GetFiles();
                foreach (FileInfo F in N_Files)
                {
                  //Make sure the file doesn't already exist.
                  N_file = "";
                  if (File.Exists(DIRS_NEW_NAME[i] + @"\" + F.Name)) {
                    //CREATE RANDOM NUMBER
                    N_file = DIRS_NEW_NAME + @"\" + F.Name + RandomClass.Next(4, 14); 
                  }
                  else { N_file = DIRS_NEW_NAME[i] + @"\" + F.Name; }
                  File.Move(F.FullName, N_file);
                  DELETE.Add(DIRS_TO_MOVE[i]);
                }
                foreach (String D in DELETE)
                {
                  Directory.Delete(D);
                }
                //directory exists so read the directory contents and move then into the folder

              }
            }
            mpSettings.Dispose(); 

            }
      }
    }

      catch (Exception ex)
     {
        DIR_WATCH.tmrTimer.Enabled = false;
        Log.Info("Data: " + ex.Data);
        Log.Info("HelpLink: " + ex.HelpLink);
        Log.Info("InnerException: " + ex.InnerException);
        Log.Info("Message: " + ex.Message);
        Log.Info("Source: " + ex.Source);
        Log.Info("StackTrace: " + ex.StackTrace);
        Log.Info("TargetSite: " + ex.TargetSite);
      }
    }
  }
}

